package cn.iocoder.yudao.framework.mybatis.config;

import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.mybatis.component.SqlCostInterceptor;
import cn.iocoder.yudao.framework.mybatis.core.mapper.CommonMapper;
import cn.iocoder.yudao.framework.mybatis.handler.MyMetaObjectHandler;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.incrementer.PostgreKeyGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;

import java.lang.reflect.InvocationTargetException;

/**
 * @className: MyBatisPlusConfiguration
 * @author: tangkh
 * @date: 2023-09-19 16:30
 */
public class MyBatisPlusConfiguration {
    private static final Logger log = LoggerFactory.getLogger(MyBatisPlusConfiguration.class);

    @Autowired(
            required = false
    )
    private TenantLineInnerInterceptor tenantLineInnerInterceptor;
    @Value("${mybatis-plus.global-config.worker-id:}")
    private Long workerId;
    @Value("${mybatis-plus.global-config.datacenter-id:}")
    private Long datacenterId;

    public MyBatisPlusConfiguration() {
    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        if (this.tenantLineInnerInterceptor != null) {
            interceptor.addInnerInterceptor(this.tenantLineInnerInterceptor);
        }

        try {
            Class<?> clazz = Class.forName("cn.iocoder.yudao.framework.mybatis.interceptor.SqlPmValueInterceptor");
            Object newInstance = clazz.getDeclaredConstructor().newInstance();
            interceptor.addInnerInterceptor((InnerInterceptor) newInstance);
        } catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException | ClassNotFoundException var4) {
            log.warn("MybatisPlusInterceptor not found class：{}", "cn.iocoder.yudao.framework.mybatis.interceptor.SqlPmValueInterceptor");
        }

        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }

    @ConditionalOnMissingBean
    @Bean
    public MyMetaObjectHandler myMetaObjectHandler(JdbcTemplate jdbcTemplate) {
        log.info("Init MyMetaObjectHandler");
        return new MyMetaObjectHandler(jdbcTemplate);
    }

    @Bean
    public CommonMapper commonMapper(SqlSessionFactory sqlSessionFactory) {
        log.info("Init CommonMapper");
        return new CommonMapper(sqlSessionFactory);
    }

    @Bean
    public IKeyGenerator keyGenerator() {
        return new PostgreKeyGenerator();
    }

    @Bean
    public IdentifierGenerator identifierGenerator() {
        if ((this.workerId != null || this.datacenterId != null) && (this.workerId >= 1L && this.workerId <= 31L || this.datacenterId >= 1L && this.datacenterId <= 31L)) {
            if (this.workerId != null && this.workerId >= 1L && this.workerId <= 31L && (this.datacenterId == null || this.datacenterId < 1L || this.datacenterId > 31L)) {
                this.datacenterId = (long) RandomUtil.randomInt(1, 31);
            } else if ((this.workerId == null || this.workerId < 1L || this.workerId > 31L) && this.datacenterId != null && this.datacenterId >= 1L && this.datacenterId <= 31L) {
                this.workerId = (long) RandomUtil.randomInt(1, 31);
            }

            log.info("create identifierGenerator bean workerId:{}, datacenterId:{}", this.workerId, this.datacenterId);
            return new DefaultIdentifierGenerator(this.workerId, this.datacenterId);
        } else {
            return new DefaultIdentifierGenerator();
        }
    }

    @ConditionalOnMissingBean({SqlCostInterceptor.class})
    @Order(-2147483648)
    @Bean
    public SqlCostInterceptor sqlCostInterceptor() {
        log.info("Init sqlCostInterceptor");
        return new SqlCostInterceptor();
    }
}
